#include "bsp_gt911.h"
// std
#include "string.h"
// lib
#include "cmsis_os.h"
#include "debug.h"
// msp
#include "sw_iic.h"
// stm32_ll_lib
#include "stm32f1xx_ll_gpio.h"
#include "stm32f1xx_ll_bus.h"



//-------------------------------------------------------------------------------------------------
//------------------------------------------修改接口------------------------------------------------
//-------------------------------------------------------------------------------------------------
#define GT911_DELAY_MS                      osDelay
// 初始化GT911的INT和RSTIO
void GT911_Init_INT_RST_GPIO()
{
    LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
    LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_GPIOA);
    LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_GPIOB);
    LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_GPIOC);
    LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_GPIOD);

    GPIO_InitStruct.Pin = GT911_RST_PIN;
    GPIO_InitStruct.Mode = LL_GPIO_MODE_OUTPUT;
    GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
    GPIO_InitStruct.Pull = LL_GPIO_PULL_UP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    LL_GPIO_Init(GT911_RST_PORT, &GPIO_InitStruct);
    GPIO_InitStruct.Pin = GT911_INT_PIN;
    GPIO_InitStruct.Mode = LL_GPIO_MODE_OUTPUT;
    GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
    GPIO_InitStruct.Pull = LL_GPIO_PULL_UP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    LL_GPIO_Init(GT911_INT_PORT, &GPIO_InitStruct);
}

// 还原GT911_INT引脚为输入模式
void GT911_Init_INT_Input(void)
{
    LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
    GPIO_InitStruct.Pin = GT911_INT_PIN;
    GPIO_InitStruct.Mode = LL_GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = LL_GPIO_PULL_DOWN;
    LL_GPIO_Init(GT911_INT_PORT, &GPIO_InitStruct);
}
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------

/**
 * @brief 向GT911写入一次数据
 *
 * @param reg 起始寄存器地址
 * @param buf 数据缓缓存区
 * @param len 写数据长度
 * @return uint8_t 0,成功;1,失败.
 */
uint8_t GT911_WR_Reg(uint16_t reg, uint8_t *buf, uint8_t len)
{
    uint8_t i;
    uint8_t ret = 0;
    SW_IIC_Start();
    SW_IIC_Send_Byte(GT_CMD_WR); // 发送写命令
    SW_IIC_Wait_Ack();
    SW_IIC_Send_Byte(reg >> 8); // 发送高8位地址
    SW_IIC_Wait_Ack();
    SW_IIC_Send_Byte(reg & 0XFF); // 发送低8位地址
    SW_IIC_Wait_Ack();
    for (i = 0; i < len; i++)
    {
        SW_IIC_Send_Byte(buf[i]); // 发数据
        ret = SW_IIC_Wait_Ack();
        if (ret)
            break;
    }
    SW_IIC_Stop(); // 产生一个停止条件
    return ret;
}

/**
 * @brief 从GT911读出一次数据
 *
 * @param reg 起始寄存器地址
 * @param buf 数据缓缓存区
 * @param len 读数据长度
 */
void GT911_RD_Reg(uint16_t reg, uint8_t *buf, uint8_t len)
{
    uint8_t i;
    SW_IIC_Start();
    SW_IIC_Send_Byte(GT_CMD_WR); // 发送写命令
    SW_IIC_Wait_Ack();
    SW_IIC_Send_Byte(reg >> 8); // 发送高8位地址
    SW_IIC_Wait_Ack();
    SW_IIC_Send_Byte(reg & 0XFF); // 发送低8位地址
    SW_IIC_Wait_Ack();
    SW_IIC_Start();
    SW_IIC_Send_Byte(GT_CMD_RD); // 发送读命令
    SW_IIC_Wait_Ack();
    for (i = 0; i < len; i++)
    {
        buf[i] = SW_IIC_Read_Byte(i == (len - 1) ? 0 : 1); // 发数据
    }
    SW_IIC_Stop(); // 产生一个停止条件
}

/**
 * @brief 初始化GT911触摸屏
 *
 * @return uint8_t 0,初始化成功;1,初始化失败
 */
uint8_t GT911_Init(void)
{
    uint8_t temp[5];

    GT911_Init_INT_RST_GPIO();              // 初始化GT911的INT和RST IO
    SW_IIC_Init();                          // 初始化电容屏的I2C总线IO

    GT911_RST_SET(0);                       // 复位
    GT911_DELAY_MS(10);
    GT911_RST_SET(1);                       // 释放复位
    GT911_DELAY_MS(10);
    GT911_Init_INT_Input();                 // 还原GT911_INT引脚为输入模式
    GT911_DELAY_MS(100);

    GT911_RD_Reg(GT_PID_REG, temp, 4);      // 读取产品ID
    temp[4] = 0;
    printf("CTP ID:%s\r\n", temp);          // 打印ID
    Printf_String_In_Hex(temp, sizeof(temp));
    if (strcmp((char *)temp, "911") == 0)   // ID==911
    {
        temp[0] = 0X02;
        GT911_WR_Reg(GT_CTRL_REG, temp, 1); // 软复位GT911
        GT911_RD_Reg(GT_CFGS_REG, temp, 1); // 读取GT_CFGS_REG寄存器
        if (temp[0] < 0X60)                 // 默认版本比较低,需要更新flash配置
        {
            printf("Default Ver:%d\r\n", temp[0]);
        }
        GT911_DELAY_MS(10);
        temp[0] = 0X00;
        GT911_WR_Reg(GT_CTRL_REG, temp, 1); // 结束复位
        return 0;
    }
    return 1;
}

const uint16_t GT911_TPX_TBL[5] = {GT_TP1_REG, GT_TP2_REG, GT_TP3_REG, GT_TP4_REG, GT_TP5_REG};

/**
 * @brief 扫描触摸屏(采用查询方式)
 * @note  mode:
 *
 * @param mode 0,正常扫描.
 * @return uint8_t 当前触屏状态.0,触屏无触摸;1,触屏有触摸
 */
uint8_t GT911_Scan(uint8_t mode)
{
    uint8_t res = 0;
#if 0
    uint8_t buf[4];
    uint8_t i = 0;
    uint8_t temp;
    static uint8_t t = 0; // 控制查询间隔,从而降低CPU占用率
    t++;
    if ((t % 10) == 0 || t < 10) // 空闲时,每进入10次CTP_Scan函数才检测1次,从而节省CPU使用率
    {
        GT911_RD_Reg(GT_GSTID_REG, &mode, 1); // 读取触摸点的状态
        // printf("mode:0x%x\r\n",mode);
        if ((mode & 0XF) && ((mode & 0XF) < 6))
        {
            temp = 0XFF << (mode & 0XF); // 将点的个数转换为1的位数,匹配tp_dev.sta定义
            tp_dev.sta = (~temp) | TP_PRES_DOWN | TP_CATH_PRES;
            for (i = 0; i < 5; i++)
            {
                if (tp_dev.sta & (1 << i)) // 触摸有效?
                {
                    GT911_RD_Reg(GT911_TPX_TBL[i], buf, 4); // 读取XY坐标值
                    // if (lcddev.dir == 0)                    // 竖屏
                    // {
                        tp_dev.x[i] = ((uint16_t)buf[1] << 8) + buf[0];
                        tp_dev.y[i] = (((uint16_t)buf[3] << 8) + buf[2]);
                    // }
                    // else // 横屏
                    // {
                    //     tp_dev.y[i] = ((uint16_t)buf[1] << 8) + buf[0];
                    //     tp_dev.x[i] = lcddev.width - (((uint16_t)buf[3] << 8) + buf[2]);
                    // }
                    printf("x[%d]:%d,y[%d]:%d\r\n", i, tp_dev.x[i], i, tp_dev.y[i]); // 串口打印坐标，用于调试
                }
            }
            res = 1;
            if (tp_dev.x[0] == 0 && tp_dev.y[0] == 0)
                mode = 0; // 读到的数据都是0,则忽略此次数据
            t = 0;        // 触发一次,则会最少连续监测10次,从而提高命中率
        }
        if (mode & 0X80 && ((mode & 0XF) < 6))
        {
            temp = 0;
            GT911_WR_Reg(GT_GSTID_REG, &temp, 1); // 清标志
        }
    }
    if ((mode & 0X8F) == 0X80) // 无触摸点按下
    {
        if (tp_dev.sta & TP_PRES_DOWN) // 之前是被按下的
        {
            tp_dev.sta &= ~(1 << 7); // 标记按键松开
        }
        else // 之前就没有被按下
        {
            tp_dev.x[0] = 0xffff;
            tp_dev.y[0] = 0xffff;
            tp_dev.sta &= 0XE0; // 清除点有效标记
        }
    }
    if (t > 240)
        t = 10; // 重新从10开始计数
#endif
    return res;
}
